package com.qzsoft.zhjd.server.socket.handler;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.qzsoft.zhjd.server.modules.env.entity.CollectEnvDataEntity;
import com.qzsoft.zhjd.server.modules.env.service.CollectEnvDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.qzsoft.zhjd.server.socket.utils.CRCUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.socket.SocketChannel;
import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName TcpEnvMessageHandler
 * @Description 环境设备消息处理
 * @author linhuawei
 * @since 2022-02-23
 */
@Slf4j
@Sharable
@Component
public class TcpEnvMessageHandler extends SimpleChannelInboundHandler<String> {

    @Autowired
    private CollectEnvDataService collectEnvDataService;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        SocketChannel socketChannel = (SocketChannel) ctx.channel();
        log.info("环境监测[{}]：{}", socketChannel.remoteAddress().toString(), msg);

        // 判断开始结束是否合法
        if (null == msg || !msg.startsWith("##") || !msg.endsWith("\r\n")) {
            log.info("设备数据不合法：{}", msg);
            return;
        }

        // 截取数据有效部分
        // 数据格式：## + 4位数据长度 + 指定长度的数据（最后两位固定位&&） + 4位CRC校验位 + \r\n
        String data = null;
//        String crc = null;
        try {
            String dataLenStr = msg.substring(2, 6);
            int dataLen = Integer.parseInt(dataLenStr);
            data = msg.substring(6, 6 + dataLen);
//            crc = msg.substring(6 + dataLen, 6 + dataLen + 4);
        } catch (Exception e) {
            log.info("获取数据有效数据失败：{}", msg);
            e.printStackTrace();
            return;
        }

        // TODO 判断CRC校验是否一致

        // 去掉有效数据固定结尾&&
        data = data.substring(0, data.length() - 2);
        String[] strs = data.split(";");
        String qn = null;// 请求编码
        String mn = null;// 设备编码
        String pw = null;// 密码
        String cn = null;// 命令码
        for (String str : strs) {
            if (str.startsWith("QN=")) {
                qn = str.substring(3);
            } else if (str.startsWith("CN=")) {
                cn = str.substring(3);
            } else if (str.startsWith("MN=")) {
                mn = str.substring(3);
            } else if (str.startsWith("PW=")) {
                pw = str.substring(3);
            }
        }

        // 判断是否数据是否为空
        if (null == qn || null == cn || null == mn || null == pw) {
            return;
        }

        // 处理数据内容
        try {
            if ("2011".equals(cn)) {// 分钟数据
                CollectEnvDataEntity envData = getMinuteData(strs);
                envData.setDeviceCode(mn);
                envData.setUploadTime(qnTODate(qn));
                collectEnvDataService.collect(envData);
            } else if ("2061".equals(cn)) {// 小时平均数据

            }
        } catch (Exception e) {
            log.error("保存数据失败：{}", msg);
        }

        // 返回结果数据
        data = "QN=" + qn + ";ST=91;CN=9014;PW=" + pw + ";MN=" + mn + ";Flag=4;CP=&&&&";
        send(socketChannel, data);
    }

    /**
     * @Title send
     * @Description 数据处理结果返回
     * @param socketChannel
     * @param data
     */
    private void send(SocketChannel socketChannel, String data) {
        String crc = CRCUtils.getCheck(data);
        String dataLenStr = String.format("%04d", data.length());
        String message = "##" + dataLenStr + data + crc + "\r\n";
        try {
            socketChannel.writeAndFlush(message).addListener(future -> {
                if (future.isSuccess()) {
                    log.info("数据回复成功：resp = {}", message);
                } else {
                    log.info("数据回复失败：resp = {}", message);
                }
            });
        } catch (Exception e) {
            log.info("数据回复异常：resp = {}, ex = {}", message, e.getMessage());
        }
    }

    /**
     * @Title getMinuteData
     * @Description 获取分钟数据
     * @return 分钟数据
     */
    private CollectEnvDataEntity getMinuteData(String[] strs) {
        CollectEnvDataEntity envData = new CollectEnvDataEntity();
        for (String str : strs) {
            if (str.startsWith("a01001")) {// 温度
                envData.setTemperature(getRtdValue(str, "a01001"));
            } else if (str.startsWith("a01002")) {// 湿度
                envData.setHumidity(getRtdValue(str, "a01002"));
            } else if (str.startsWith("a34001")) {// 总悬浮颗粒物tsp
                envData.setTsp(getRtdValue(str, "a34001"));
            } else if (str.startsWith("a34002")) {// pm10
                envData.setPm10(getRtdValue(str, "a34002"));
            } else if (str.startsWith("a34004")) {// pm2.5
                envData.setPm2d5(getRtdValue(str, "a34004"));
            } else if (str.startsWith("LA")) {// 噪声，这个是看标准文档里面用的这个字段
                envData.setNoise(getRtdValue(str, "LA"));
            }
        }
        return envData;
    }

    /**
     * @Title getRtdValue
     * @Description 获取采集数据
     * @param str  数据内容
     * @param code 数据编码
     * @return 结果数据
     */
    private BigDecimal getRtdValue(String str, String code) {
        String[] strs = str.split(",");
        String rtdCode = code + "-Rtd=";
        String rtdValue = null;
        for (String temp : strs) {
            if (temp.startsWith(rtdCode)) {
                rtdValue = temp.substring(rtdCode.length());
                break;
            }
        }
        return null == rtdValue ? null : new BigDecimal(rtdValue);
    }

    /**
     * @Title qnTODateStr
     * @Description 采集数据中的时间字符串转日期字符串
     * @param qn
     * @return
     */
    private Date qnTODate(String qn) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        try {
            return sdf.parse(qn);
        } catch (Exception e) {
            return null;
        }
    }

}
